using System;

namespace ValidationFramework.Specifications
{
    /// <summary>
    /// Performs a string length validation.
    /// </summary>
    /// <seealso cref="LengthStringRuleConfigReader"/>
	/// <seealso cref="LengthStringRuleAttribute"/>
#if (!SILVERLIGHT)
    [Serializable]
#endif
    public class HasLengthInRangeSpec : LengthInRangeBase
    {
        // --- Constructors

        /// <exception cref="ArgumentNullException"><paramref name="maximum"/> is not greater than or equal to <paramref name="minimum"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="minimum"/> is less than 0.</exception>
        /// <param name="maximum">The maximum length allowed.</param>
        /// <param name="minimum">The minimum length allowed.</param>
        public HasLengthInRangeSpec(int minimum, int maximum)
            : this(minimum, maximum, true)
        {
        }

        /// <param name="maximum">The maximum length allowed.</param>
        /// <param name="minimum">The minimum length allowed.</param>
        /// <param name="trimWhiteSpace">A <see cref="bool"/> to indicate if whitespace should be trimmed from the value being validated.</param>
        /// <exception cref="ArgumentNullException"><paramref name="minimum"/> is less than 0.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="maximum"/> is not greater than or equal to <paramref name="minimum"/>.</exception>
        public HasLengthInRangeSpec(int minimum, int maximum, bool trimWhiteSpace)
			: base(minimum, maximum)
        {
            TrimWhiteSpace = trimWhiteSpace;
        }


        // --- Properties

        /// <summary>
        /// Gets a <see cref="bool"/> to indicate if whitespace should be trimmed from the value being validated.
        /// </summary>
        public bool TrimWhiteSpace
        {
			get;
			set;
        }


        // --- Methods

		/// <inheritdoc />
		public override string DefaultMessage(string tokenizedMemberName, string descriptorType)
		{
			if (Minimum == Maximum)
			{
				return string.Format("The {0} '{1}' must be {2} characters in length.", descriptorType, tokenizedMemberName, Minimum);
			}
			else
			{
				return string.Format("The {0} '{1}' must be between {2} and {3} characters in length.", descriptorType, tokenizedMemberName, Minimum, Maximum);
			}
		}

		/// <inheritdoc />
		public override string ToString()
		{
			if (Minimum == Maximum)
			{
				return string.Format("The value must be {0} characters in length.", Minimum);
			}
			else
			{
				return string.Format("The value must be between {0} and {1} characters in length.", Minimum, Maximum);
			}
		}

		/// <inheritdoc />
		public override bool IsEquivalentTo(ISpecification spec)
		{
			return base.IsEquivalentTo(spec) 
				&& ((HasLengthInRangeSpec)spec).TrimWhiteSpace == TrimWhiteSpace;
		}

		/// <inheritdoc />
		public override bool IsSatisfiedBy(object target)
		{
			if (target != null)
            {
				var valueAsString = (string)target;
                if (TrimWhiteSpace)
                {
                    valueAsString = valueAsString.Trim();
                }
                return LengthValidationHelper.IsLengthValid(valueAsString.Length, Minimum, Maximum);
            }
            return true;
		}

		public override bool CanBeSatisfiedBy(Type typeToTest)
		{
			return base.CanBeSatisfiedBy(typeToTest) && typeToTest == typeof(string);
		}
    }
}